/**
 * 反爬虫
 * @returns {boolean}
 */
export function crawler() {
  // 无头模式下的UA会带有HeadlessChrome关键字
  if (/HeadlessChrome/.test(navigator.userAgent)) return false
  // 无头模式下navigator.webdriver为true
  if (navigator.webdriver) return false
  // 无头模式下window.chrome属性是undefined
  if (!window.chrome) return false
  // 无头模式下Notification.permission与navigator.permissions.query会返回相反的值
  const permissionStatus = navigator.permissions.query({name: 'notifications'})
  if (Notification.permission === 'denied' && permissionStatus.state === 'prompt') return false
  // 无头模式下navigator.plugins.length返回0
  if (navigator.plugins.length === 0) return false
  // 无头模式下navigator.languages为空
  return !(!navigator.languages || navigator.languages.length === 0);
  // console.log({
  //   'navigator.webdriver': navigator.webdriver,
  //   'window.chrome': window.chrome,
  //   'Notification.permission': Notification.permission,
  //   'permissionStatus.state': permissionStatus.state,
  //   'navigator.plugins': navigator.plugins,
  //   'navigator.languages': navigator.languages
  // })
}

/**
 * 获取设备信息
 * @returns {{"window.doNotTrack": string, webGlInfo: ({MAX_VERTEX_ATTRIBS: *, RED_BITS: *, MAX_COMBINED_TEXTURE_IMAGE_UNITS: *, ALIASED_LINE_WIDTH_RANGE: *, anisotropicExt: *, MAX_FRAGMENT_UNIFORM_VECTORS: *, BLUE_BITS: *, MAX_RENDERBUFFER_SIZE: *, fragmentShaderBestPrecision: number, WEBGL_draw_buffers: *, MAX_DRAW_BUFFERS_WEBGL: *|null, fragmentShaderFloatIntPrecision: *, SHADING_LANGUAGE_VERSION: *, ALIASED_POINT_SIZE_RANGE: *, MAX_TEXTURE_SIZE: *, MAX_CUBE_MAP_TEXTURE_SIZE: *, MAX_VIEWPORT_DIMS: *, MAX_VARYING_VECTORS: *, MAX_VERTEX_TEXTURE_IMAGE_UNITS: *, MAX_VERTEX_UNIFORM_VECTORS: *, UNMASKED_VENDOR_WEBGL: *, GREEN_BITS: *, getSupportedExtensions: *, maxVertexTextureImageUnits: number, STENCIL_BITS: *, RENDERER: *, STENCIL_TEST: *, UNMASKED_RENDERER_WEBGL: *, MAX_TEXTURE_IMAGE_UNITS: *, DEPTH_BITS: *, VERSION: *, VENDOR: *, ALPHA_BITS: *}|{error: *}), "window.innerHeight": number, timezone: (*|{}|{error: *}), "window.deviceorientation": ("undefined"|"object"|"boolean"|"number"|"string"|"function"|"symbol"|"bigint"|*), "window.outerHeight": number, "window.performance": (*|{}|{error: *}), "window.speed": *, timezoneOffset: number, "window.navigator": (*|{}|{error: *}), "window.chrome": (*|{}|{error: *}), "window.eval.toString().length": number, "window.outerWidth": number, "window.screen": (*|{}|{error: *}), "window.history.length": number, "window.devicePixelRatio": number, "window.ontouchstart": (this:GlobalEventHandlers, ev: TouchEvent) => any, "window.innerWidth": number}}
 */
export function getDeviceInfo() {

  function getObjAttributes(obj, filter) {

    try {

      if (!obj) {
        return obj;
      }

      let keyList = [];
      for (let attr in obj) {
        keyList.push(attr);
      }

      if (keyList.length < 1) {
        return {}
      }

      return keyList.reduce(function (total, curr) {

        let value = null;

        if (!filter || !filter(obj, curr)) {
          let objType = typeof obj[curr];
          if (objType === 'function') {
            value = obj[curr].toString();
          } else if (objType === 'object') {
            value = getObjAttributes(obj[curr], filter);
          } else {
            value = obj[curr];
          }
        }
        return {
          ...total,
          [curr]: value
        };
      }, {});
    } catch (err) {
      return {
        "error": err.stack
      }
    }
  }

  function webglInfo() {
    try {
      let canvasEle = document.createElement("canvas");
      let webglCtx = canvasEle.getContext("experimental-webgl");
      let webglDrawBuffers = webglCtx.getExtension("WEBGL_draw_buffers");
      let webglDebugRenderInfo = webglCtx.getExtension("WEBGL_debug_renderer_info");
      let anisotropic = webglCtx.getExtension("EXT_texture_filter_anisotropic") || webglCtx.getExtension("WEBKIT_EXT_texture_filter_anisotropic") || webglCtx.getExtension("MOZ_EXT_texture_filter_anisotropic");
      let anisotropicExt = webglCtx.getParameter(anisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
      let maxVertexTextureImageUnits = webglCtx.getShaderPrecisionFormat ? webglCtx.getShaderPrecisionFormat(webglCtx.VERTEX_SHADER, webglCtx.MEDIUM_FLOAT).precision : 0;
      let fragmentShaderBestPrecision = webglCtx.getShaderPrecisionFormat ? webglCtx.getShaderPrecisionFormat(webglCtx.FRAGMENT_SHADER, webglCtx.MEDIUM_FLOAT).precision : 0;
      let fragmentShaderFloatIntPrecision = (webglCtx.getShaderPrecisionFormat(webglCtx.FRAGMENT_SHADER, webglCtx.HIGH_FLOAT).precision ? "highp/" : "mediump/") + (webglCtx.getShaderPrecisionFormat(webglCtx.FRAGMENT_SHADER, webglCtx.HIGH_INT).rangeMax ? "highp" : "lowp")

      return {
        "WEBGL_draw_buffers": webglDrawBuffers,
        "MAX_DRAW_BUFFERS_WEBGL": webglDrawBuffers ? webglCtx.getExtension(webglDrawBuffers.MAX_DRAW_BUFFERS_WEBGL) : null,
        "RENDERER": webglCtx.getParameter(webglCtx.RENDERER),
        "VENDOR": webglCtx.getParameter(webglCtx.VENDOR),
        "VERSION": webglCtx.getParameter(webglCtx.VERSION),
        "UNMASKED_RENDERER_WEBGL": webglCtx.getParameter(webglDebugRenderInfo.UNMASKED_RENDERER_WEBGL),
        "UNMASKED_VENDOR_WEBGL": webglCtx.getParameter(webglDebugRenderInfo.UNMASKED_VENDOR_WEBGL),
        "STENCIL_TEST": webglCtx.isEnabled(webglCtx.STENCIL_TEST),
        "SHADING_LANGUAGE_VERSION": webglCtx.getParameter(webglCtx.SHADING_LANGUAGE_VERSION),
        "RED_BITS": webglCtx.getParameter(webglCtx.RED_BITS),
        "GREEN_BITS": webglCtx.getParameter(webglCtx.GREEN_BITS),
        "BLUE_BITS": webglCtx.getParameter(webglCtx.BLUE_BITS),
        "ALPHA_BITS": webglCtx.getParameter(webglCtx.ALPHA_BITS),
        "MAX_RENDERBUFFER_SIZE": webglCtx.getParameter(webglCtx.MAX_RENDERBUFFER_SIZE),
        "MAX_COMBINED_TEXTURE_IMAGE_UNITS": webglCtx.getParameter(webglCtx.MAX_COMBINED_TEXTURE_IMAGE_UNITS),
        "MAX_CUBE_MAP_TEXTURE_SIZE": webglCtx.getParameter(webglCtx.MAX_CUBE_MAP_TEXTURE_SIZE),
        "MAX_FRAGMENT_UNIFORM_VECTORS": webglCtx.getParameter(webglCtx.MAX_FRAGMENT_UNIFORM_VECTORS),
        "MAX_TEXTURE_IMAGE_UNITS": webglCtx.getParameter(webglCtx.MAX_TEXTURE_IMAGE_UNITS),
        "MAX_TEXTURE_SIZE": webglCtx.getParameter(webglCtx.MAX_TEXTURE_SIZE),
        "MAX_VARYING_VECTORS": webglCtx.getParameter(webglCtx.MAX_VARYING_VECTORS),
        "MAX_VERTEX_ATTRIBS": webglCtx.getParameter(webglCtx.MAX_VERTEX_ATTRIBS),
        "MAX_VERTEX_UNIFORM_VECTORS": webglCtx.getParameter(webglCtx.MAX_VERTEX_UNIFORM_VECTORS),
        "ALIASED_LINE_WIDTH_RANGE": webglCtx.getParameter(webglCtx.ALIASED_LINE_WIDTH_RANGE),
        "ALIASED_POINT_SIZE_RANGE": webglCtx.getParameter(webglCtx.ALIASED_POINT_SIZE_RANGE),
        "MAX_VIEWPORT_DIMS": webglCtx.getParameter(webglCtx.MAX_VIEWPORT_DIMS),
        "anisotropicExt": anisotropicExt,
        "maxVertexTextureImageUnits": maxVertexTextureImageUnits,
        "MAX_VERTEX_TEXTURE_IMAGE_UNITS": webglCtx.getParameter(webglCtx.MAX_VERTEX_TEXTURE_IMAGE_UNITS),
        "fragmentShaderBestPrecision": fragmentShaderBestPrecision,
        "DEPTH_BITS": webglCtx.getParameter(webglCtx.DEPTH_BITS),
        "STENCIL_BITS": webglCtx.getParameter(webglCtx.STENCIL_BITS),
        "getSupportedExtensions": webglCtx.getSupportedExtensions(),
        "fragmentShaderFloatIntPrecision": fragmentShaderFloatIntPrecision
      };
    } catch (err) {
      return {
        "error": err.stack
      }
    }
  }

  return {
    "window.navigator": getObjAttributes(navigator, (obj, name) => name === 'enabledPlugin'),
    "window.screen": getObjAttributes(window.screen),
    "window.innerHeight": window.innerHeight,
    "window.innerWidth": window.innerWidth,
    "window.outerHeight": window.outerHeight,
    "window.outerWidth": window.outerWidth,
    "window.history.length": window.history.length,
    "window.performance": getObjAttributes(window.performance),
    "window.eval.toString().length": window.eval.toString().length,
    "window.devicePixelRatio": window.devicePixelRatio,
    "window.speed": window.speed,
    "window.deviceorientation": !window.deviceorientation ? (typeof window.deviceorientation) : window.deviceorientation,
    "window.ontouchstart": window.ontouchstart,
    "window.doNotTrack": window.doNotTrack,
    "window.chrome": getObjAttributes(window.chrome),
    "timezoneOffset": (new Date).getTimezoneOffset(),
    "timezone": getObjAttributes(new window.Intl.DateTimeFormat().resolvedOptions()),
    "webGlInfo": webglInfo()
  };
}
